
from constantes import *
from jugador import Jugador
import time
import random

class JugadorInteligente(Jugador):
	"""
	Este jugador va a ganar el torneo!

	(Escribir codigo de aca para abajo)
	"""
	def __init__(self, color, nombre):
		self.color = color
		self.nombre = nombre
	 	self.continente_conquistar = ""
	 	self.ronda = 0
	 	self.ronda_espera = 0
	 	self.suicidas = []

	def atacar(self, tablero, paises_ganados_ronda):
		mis_paises = tablero.paises_color(self.color)
		for pais in mis_paises:
			if tablero.ejercitos_pais(pais) < 3:
				continue

			if tablero.continente_pais(pais) == self.continente_conquistar:
				limitrofes_ataque = {}
				limitrofes_defensa = {}
				for limitrofe in tablero.paises_limitrofes(pais):
					if tablero.color_pais(limitrofe) == self.color:
						#no me puedo atacar a mi mismo
						continue
					self._obtener_limitrofes_para_atacar(tablero, limitrofes_ataque, limitrofes_defensa,\
						 limitrofe)

				#ataco primero a los limitrofes que tienen menos ejercitos y que poseo mayores ejercitos.
				for ejercitos_defensa in sorted(limitrofes_defensa.values()):
					for limitrofe in limitrofes_defensa:
						"""#Es un jugador suicida
						if (limitrofes_defensa[limitrofe] >= 50 and self.ronda <= 20) or\
							 (limitrofe in self.suicidas):
							self.suicidas.append(limitrofe)
							continue"""

						if (limitrofes_defensa[limitrofe] == ejercitos_defensa) and\
							 (limitrofes_ataque[limitrofe] >= ejercitos_defensa):
							return pais, limitrofe

		#ataco con los demas paises que no pertenecen al continente a conquistar que posean mas de 3 ejercitos.
			if (tablero.ejercitos_pais(pais) > 3):
				for limitrofe in tablero.paises_limitrofes(pais):
					if tablero.color_pais(limitrofe) == self.color:
						#no me puedo atacar a mi mismo
						continue
					else:
						return pais, limitrofe

		return None

	def _obtener_limitrofes_para_atacar(self, tablero, limitrofes_ataque, limitrofes_defensa, limitrofe):
		"""	Recibe por parametro el tablero, instancia de la clase Tablero, los diccionarios limitrofes_ataque
			 y limitrofes_defensa, inicialmente vacios y limitrofe, que es una cadena.
			Modifica los diccionarios pasados por parametro, limitrofes_ataque posee como claves los limitrofes
			 enemigos y como valores los ejercitos con los que lo puedo atacar al limitrofe, y limitrofes_defensa
			 posee como claves los limitrofes enemigos y como valores los ejercitos que poseen.
			Este metodo privado no devuelve ningun valor.
		"""
		ejercitos_atacar = 0
		for limitrofe_mio in tablero.paises_limitrofes(limitrofe):
			if tablero.color_pais(limitrofe_mio) == self.color:
				ejercitos_atacar += tablero.ejercitos_pais(limitrofe_mio)-1

		limitrofes_ataque[limitrofe] = ejercitos_atacar
		limitrofes_defensa[limitrofe] = tablero.ejercitos_pais(limitrofe)

	def ronda_iniciada(self, tablero, ronda, orden_ronda):
		self.ronda = ronda

	def agregar_ejercitos(self, tablero, cantidad):
		#Este diccionario posee como claves los nombres de los continentes y como sus respectivos valores
		#los paises de este continente que lo conectan con otro.
		paises_conectores = {
			'Africa': ['Sahara', 'Egipto'],
			'America del Sur': ['Brasil', 'Chile', 'Colombia'],
			'America del Norte': ['Alaska', 'Groenlandia'],
			'Asia': ['Aral', 'Kamchatka', 'Turquia', 'Iran'],
			'Europa': ['Polonia', 'Espana', 'Islandia', 'Rusia'],
			'Oceania': ['Australia', 'Borneo', 'Sumatra']}

		paises_ejercitos = {}
		#Obtengo el continente a conquistar si es la primer ronda o si me quede sin paises en el continente.
		if (self.ronda == 1) or\
			not any(tablero.color_pais(pais) == self.color for pais in tablero.paises(self.continente_conquistar)):
			self._obtener_continente_conquistar(tablero)

		for continente in cantidad:
			if self._es_continente_completo(tablero, self.continente_conquistar):
				self.ronda_espera += 1
				if self.ronda_espera == 4:
					self.continente_conquistar = self._obtener_proximo_continente(tablero, self.continente_conquistar)
					self.ronda_espera = 0

			if (continente == ""):
				paises_agregar = self._obtener_paises_agregar(tablero, self.continente_conquistar, paises_conectores)
			else:
				paises_agregar = self._obtener_paises_agregar(tablero, continente, paises_conectores)

			if paises_agregar == []:
				paises_agregar = tablero.paises_color(self.color)

			ejercitos = cantidad[continente]
			total_paises = len(paises_agregar)
			if total_paises >= 10:
				total_paises = 9
			while ejercitos > 0:
				#Regla de tres simples, se saca el porcentaje que le corresponde al pais con 
				#respecto a los ejercitos disponibles. Se redondea el numero: si la parte decimal
				#es menor a 5 hacia abajo, si es mayor o igual a 5 hacia arriba.
				ejercitos_colocar = int(round(float(((10-total_paises) * 10) * ejercitos) / 100))
				paises_ejercitos[paises_agregar[total_paises-1]] = paises_ejercitos.get(\
						paises_agregar[total_paises-1], 0) + ejercitos_colocar
				total_paises -= 1
				ejercitos -= ejercitos_colocar

		return paises_ejercitos

	def _es_continente_completo(self, tablero, continente):
		"""	Recibe por parametro el tablero, instancia de la clase Tablero y un
			continente, que es una cadena.
			Devuelve True si el jugador posee todos los paises del continente,
			en caso contrario devuelve False.
		"""
		#Si la ronda es mayor o igual a 50 comienzo a atacar a los suicidas.
		if (self.ronda >= 50):
			self.suicidas = []

		for pais in tablero.paises(continente):
			if (tablero.color_pais(pais) != self.color) and (pais not in self.suicidas):
				return False
		return True

	def _obtener_proximo_continente(self, tablero, actual_continente):
		"""Recibe por parametro el tablero, instancia de la clase Tablero y un
			actual_continente, que es una cadena.
			 Decide cual es el proximo continente a conquistar. Primero se deben conquistar
			los continentes1 y luego los continentes2, ganando asi el juego. Sus claves son
			los continentes a conquistar y sus valores los proximos continentes a conquistar de
			acuerdo al continente actual.
			 Devuelve el proximo continente a conquistar, que es una cadena.
		"""
		continente_conquistado = actual_continente
		continentes1 = {'America del Sur':['America del Norte', 'Africa'], 
						'America del Norte': ['America del Sur', 'Africa', 'America del Norte'], 
						'Africa':['America del Sur', 'America del Norte']}

		continentes2 = {'Europa':['Asia'], 'Asia':['Europa', 'Asia', 'Oceania'], 'Oceania':['Asia']}

		for continentes in continentes1, continentes2:
			#Los continentes1 ya estan todos completos, se comienza a conquistar los continentes2
			if continentes == continentes2 and not any(not self._es_continente_completo(tablero, continente)\
				 for continente in continentes1):
				#El primero que quiero conquistar de los continentes2 es Europa.
				actual_continente = 'Asia'
			#Si no estan todos los continentes1 completos, comienzo verificando por America del Sur.
			else:
				continentes = continentes1
				actual_continente = 'America del Norte'

			for continente in continentes:
				if continente == actual_continente:
					for prox_continente in continentes[continente]:
						if (not self._es_continente_completo(tablero, prox_continente)) and \
						self._pais_propio_en_continente(tablero, prox_continente):
							return prox_continente

		return continente_conquistado

	def _pais_propio_en_continente(self, tablero, continente):
		"""	Recibe por parametro el tablero, instancia de la clase Tablero y un
		continente, que es una cadena.
			Devuelve True si el jugador posee un pais en el continente, de lo contrario
			devuelve False.
		"""
		for pais in tablero.paises(continente):
			if tablero.color_pais(pais) == self.color:
				return True
		return False

	def _obtener_paises_agregar(self, tablero, continente, paises_conectores):
		"""	Recibe por parametro el tablero, instancia de la clase Tablero, un
			continente, que es una cadena y paises_conectores que es un diccionario.
			 El diccionario paises_agregar posee como claves los paises en el
			continente a conquistar del jugador y como valores la cantidad de
			paises limitrofes enemigos que tienen.
			 Devuelve los paises(lista) para agregar ejercitos, ordenados de acuerdo 
			al criterio descripto en el metodo privado _paises_agregar_oredenados.
		"""
		paises_agregar = {}
		for pais in tablero.paises(continente):
			if tablero.color_pais(pais) == self.color:
				for limitrofe in tablero.paises_limitrofes(pais):
					if (tablero.color_pais(limitrofe) != self.color) and (limitrofe not in self.suicidas):
						paises_agregar[pais] = paises_agregar.get(pais, 0) + 1

		#Si todos los paises del continente no estan rodeados por enemigos se agregan
		#los ejercitos en los paises conectores.
		if paises_agregar == {}:
			if continente == "":
				continente_agregar = paises_conectores[self.continente_conquistar]
			else:
				continente_agregar = paises_conectores[continente]
			for pais in continente_agregar:
				if tablero.color_pais(pais) == self.color:
					paises_agregar[pais] = 1

		return self._paises_agregar_ordenados(paises_agregar)

	def _paises_agregar_ordenados(self, paises_agregar):
		"""	Recibe por parametro los paises_agregar, que es un diccionario.
			 Devuelve los paises_agregar en una lista, ordenados de menor a
			mayor de acuerdo a los paises limitrofes enemigos que tienen.
		"""
		paises_agregar_ordenados = []
		limitrofes_enemigos = sorted(paises_agregar.values())
		for pais in paises_agregar:
			for limitrofe_enemigo in limitrofes_enemigos:
				if (paises_agregar[pais] == limitrofe_enemigo) and (pais not in paises_agregar_ordenados):
					paises_agregar_ordenados.append(pais)
					break
		return paises_agregar_ordenados

	def _obtener_continente_conquistar(self, tablero):
		"""	Recibe por parametro el tablero, instancia de la clase Tablero.
			 El diccionario posibles_continentes posee los continentes que se
			consideraron mejores estrategicamente como claves y como valores
			la cantidad de paises que el jugador posee en el.
			 Asigna el continente(cadena) que posee mas paises del jugador a
			el atributo continente_conquistar. No devuelve ningun valor.
		"""
		posibles_continentes = {"America del Sur":0, "America del Norte":0, "Africa":0, "Europa":0, "Oceania":0,"Asia":0}
		for continente in posibles_continentes:
			for pais in tablero.paises(continente):
				if tablero.color_pais(pais) == self.color:
					posibles_continentes[continente] += 1

		max_cant_paises = max(posibles_continentes.values())
		for continente in posibles_continentes:
			if posibles_continentes[continente] == max_cant_paises:
				self.continente_conquistar = continente

	def mover(self, desde, hacia, tablero, paises_ganados_ronda):
		if (tablero.ejercitos_pais(desde) >= 8):
			return 3
		else:
			return 1

	def reagrupar(self, tablero, paises_ganados_ronda):
		paises_reagrupar = []
		mis_paises = tablero.paises_color(self.color)
		for pais in mis_paises:
			#Reagrupo si el pais no esta rodeado por paises enemigos.
			if not any(tablero.color_pais(limitrofe1) != self.color for limitrofe1 in tablero.paises_limitrofes(pais)):
				for limitrofe1 in tablero.paises_limitrofes(pais):
					#Reagrupo en algun pais limitrofe que este reodeado por un pais enemigo.
					if any(tablero.color_pais(limitrofe2) != self.color for limitrofe2 in tablero.paises_limitrofes(limitrofe1)):
						paises_reagrupar.append((pais, limitrofe1, tablero.ejercitos_pais(pais)-1))
						break

				#todos los limitrofes del pais no estan reodeados por paises enemigos.
				if paises_reagrupar == []:
					#agrupo los paises en cualquier pais limitrofe.
					paises_reagrupar.append((pais, tablero.paises_limitrofes(pais)[random.randint(0,\
						 len(tablero.paises_limitrofes(pais))-1)], tablero.ejercitos_pais(pais)-1))

		return paises_reagrupar
